package com.vtech.mybatis.baseservice.plugins;

import com.vtech.mybatis.baseservice.util.PluginUtil;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.Plugin;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.api.dom.xml.Document;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.config.MergeConstants;
import org.mybatis.generator.internal.util.StringUtility;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * TODO
 * 扩展mybatis生成器插件，生成的Mapper接口继承基类<br/>
 * 参考了:<br/>
 * 1)开源项目：abel533/Mapper<br/>
 * 2)插件开发：http://mbg.cndocs.tk/reference/pluggingIn.html<br/>
 * 顺序：setContext-->setProperties-->validate-->
 *
 * @author houzhiwei
 * @Date 2015年12月13日 下午3:25:06
 */
public class ExtendedMapperPlugin extends PluginAdapter {
    // 如果该方法返回false ，那么插件中的其他方法都不会再被调用。
    @Override
    public boolean validate(List<String> warnings) {
        return true;
    }

    /**
     * 生成的Mapper接口:继承BaseMapper，不写常规的GRUD方法 <br/>
     * 有多个主键的类或接口，需要自己写实现
     */
   /* @Override
    public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        // 获取实体类
        FullyQualifiedJavaType entityType = new FullyQualifiedJavaType(introspectedTable.getBaseRecordType());
        StringBuilder superInterface = new StringBuilder();
        FullyQualifiedJavaType rootInterfaceType = null;
        int keySize = introspectedTable.getPrimaryKeyColumns().size();
        // 根接口
        // 参考源码：org.mybatis.generator.codegen.ibatis2.dao.DAOGenerator
        String rootInterface = properties.getProperty("rootInterface");
        if (!StringUtility.stringHasValue(rootInterface)) {
            rootInterface = "com.vtech.mybatis.baseservice.base.BaseMapper";
        }
        // 只有唯一主键时使用
        if (keySize == 1) {
            // 主键类型
            FullyQualifiedJavaType primaryKeyType = new FullyQualifiedJavaType(introspectedTable.getPrimaryKeyColumns().get(0).getFullyQualifiedJavaType().getShortName());

            rootInterfaceType = new FullyQualifiedJavaType(rootInterface);
            // import接口
            interfaze.addImportedType(primaryKeyType);

            superInterface.append(rootInterfaceType.getShortName());
            superInterface.append("<");
            superInterface.append(entityType.getShortName());
            superInterface.append(",");
            superInterface.append(primaryKeyType.getShortName());
            superInterface.append(">");

        } else if (keySize == 0)// 无主键
        {
            rootInterface = PluginUtil.insertStr(rootInterface.lastIndexOf('.') + 1, "NK", rootInterface);// 无主键
            rootInterfaceType = new FullyQualifiedJavaType(rootInterface);
            // import接口
            superInterface.append(rootInterfaceType.getShortName());
            superInterface.append("<");
            superInterface.append(entityType.getShortName());
            superInterface.append(">");

        }
        interfaze.addSuperInterface(new FullyQualifiedJavaType(superInterface.toString()));
        interfaze.addAnnotation("@Repository");
        interfaze.addImportedType(new FullyQualifiedJavaType("org.springframework.stereotype.Repository"));
        interfaze.addImportedType(rootInterfaceType);
        // import实体类
        interfaze.addImportedType(entityType);
        return true;
    }
    */

    //方法的xml内容
    @Override
    public boolean sqlMapDocumentGenerated(Document document, IntrospectedTable introspectedTable) {
        //数据库类型：oracle时必须要配置，其他可以不配置
        String dbType = properties.getProperty("dbType");
        //当targetRuntime="MyBatis3Simple"时不会生成Base_Column_List的sql，那么就自己生成
        String targetRuntime = this.context.getTargetRuntime();
        if ("MyBatis3Simple".equalsIgnoreCase(targetRuntime)) {
            XmlElement allSql = PluginUtil.generatorBaseColumnListElement(introspectedTable);
            document.getRootElement().addElement(allSql);
        }
        //额外方法（按列查询、删除）
        AdditionalMethodsSqlMap addMethodsSqlMap = new AdditionalMethodsSqlMap();

        //DeleteByColumn
        addMethodsSqlMap.generateDeleteByColumnSqlMap(document, introspectedTable, this.context);
        //SelectByColumn
        addMethodsSqlMap.generateSelectByColumnSqlMap(document, introspectedTable, false, this.context);
        //SelectByColumnWithBLOBs
        if (introspectedTable.getRules().generateResultMapWithBLOBs()) {
            addMethodsSqlMap.generateSelectByColumnSqlMap(document, introspectedTable, true, this.context);
        }

        //批量方法
        BatchMethodsSqlMap batchMethodsSqlMap = new BatchMethodsSqlMap();
        batchMethodsSqlMap.setDbType(dbType);
        batchMethodsSqlMap.generateAllBatchSqlMaps(document, introspectedTable, this.context);
        //默认部分
        return super.sqlMapDocumentGenerated(document, introspectedTable);
    }

    /*
     * return false表示不生成相应的代码
     */
    Method clientMethod;
    Interface clientInterface;
    TopLevelClass clientClass;

    @Override
    public boolean clientDeleteByPrimaryKeyMethodGenerated(Method method,
                                                           Interface interfaze, IntrospectedTable introspectedTable) {
        clientMethod = method;
        clientInterface = interfaze;
        return false;//Mapper里面不生成代码
    }
/*
    @Override
    public boolean clientDeleteByPrimaryKeyMethodGenerated(Method method,
                                                           TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        clientClass = topLevelClass;
        return false;
    }*/

    @Override
    public boolean clientInsertMethodGenerated(Method method, Interface interfaze,
                                               IntrospectedTable introspectedTable) {
        return false;
    }

   /* @Override
    public boolean clientInsertMethodGenerated(Method method,
                                               TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        return false;
    }*/

    @Override
    public boolean clientSelectByPrimaryKeyMethodGenerated(Method method,
                                                           Interface interfaze, IntrospectedTable introspectedTable) {
        return false;
    }
/*

    @Override
    public boolean clientSelectByPrimaryKeyMethodGenerated(Method method,
                                                           TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        return false;
    }
*/

    @Override
    public boolean clientUpdateByPrimaryKeySelectiveMethodGenerated(Method method,
                                                                    Interface interfaze, IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean clientUpdateByPrimaryKeyWithoutBLOBsMethodGenerated(
            Method method, Interface interfaze,
            IntrospectedTable introspectedTable) {
        return false;
    }

    @Override
    public boolean clientSelectAllMethodGenerated(Method method,
                                                  Interface interfaze, IntrospectedTable introspectedTable) {
        return false;
    }

    /*------------------------------ 给实体类字段和getset方法生成注释 --------------------------*/


    @Override
    public boolean modelPrimaryKeyClassGenerated(TopLevelClass topLevelClass,
                                                 IntrospectedTable introspectedTable) {
        generateToString(introspectedTable, topLevelClass);
        return true;
    }

    @Override
    public boolean modelRecordWithBLOBsClassGenerated(
            TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        generateToString(introspectedTable, topLevelClass);
        return true;
    }

    @Override
    public boolean modelFieldGenerated(Field field,
                                       TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn,
                                       IntrospectedTable introspectedTable,
                                       Plugin.ModelClassType modelClassType) {
        generateToString(introspectedTable, topLevelClass);
        return true;
    }

    /**
     * 实体类
     */
    @Override
    public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass,
                                                 IntrospectedTable introspectedTable) {
        generateToString(introspectedTable, topLevelClass);
        return true;
    }

    @Override
    public boolean modelSetterMethodGenerated(Method method,
                                              TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn,
                                              IntrospectedTable introspectedTable,
                                              Plugin.ModelClassType modelClassType) {
        method.addJavaDocLine("/**");
        addJavadocTag(method, false);
        method.addJavaDocLine(" */");
        return true;
    }

    @Override
    public boolean modelGetterMethodGenerated(Method method,
                                              TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn,
                                              IntrospectedTable introspectedTable,
                                              Plugin.ModelClassType modelClassType) {
        method.addJavaDocLine("/**");
        addJavadocTag(method, false);
        method.addJavaDocLine(" */");
        return true;
    }

    /**
     * 生成实体类字段注释
     *
     * @param introspectedTable
     * @param topLevelClass
     * @date at 2015年12月14日下午10:53:58
     */
    private void generateToString(IntrospectedTable introspectedTable, TopLevelClass topLevelClass) {
        List<Field> fields = topLevelClass.getFields();
        Map<String, Field> map = new HashMap<String, Field>();
        for (Field field : fields) {
            map.put(field.getName(), field);
        }
        List<IntrospectedColumn> columns = introspectedTable.getAllColumns();

        for (IntrospectedColumn column : columns) {
            Field f = map.get(column.getJavaProperty());
            if (f != null) {
                f.getJavaDocLines().clear();
                if (StringUtility.stringHasValue(column.getRemarks())) {
                    f.addJavaDocLine("/**");
                    StringBuilder sb = new StringBuilder();
                    sb.append(" * ");
                    sb.append(column.getRemarks());
                    f.addJavaDocLine(sb.toString());
                    addJavadocTag(f, false);
                    f.addJavaDocLine(" */");
                }
            }
        }
    }

    /**
     * 添加表示生成器生成的标记 @mgbgenerated,避免再次生成
     *
     * @param javaElement
     * @param markAsDoNotDelete
     * @date at 2015年12月14日下午10:54:16
     */
    protected void addJavadocTag(JavaElement javaElement,
                                 boolean markAsDoNotDelete) {
        StringBuilder sb = new StringBuilder();
        sb.append(" * "); //$NON-NLS-1$
        sb.append(MergeConstants.NEW_ELEMENT_TAG);
        if (markAsDoNotDelete) {
            sb.append(" do_not_delete_during_merge"); //$NON-NLS-1$
        }
        javaElement.addJavaDocLine(sb.toString());
    }

}
